home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / PrintingLibraries / ShapeUtilitiesPaths.c < prev   
Encoding:
Text File  |  2000-09-28  |  11.4 KB  |  329 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        ShapeUtilitiesPaths.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.      
  6.                  DissectPath() converts a polygon or path shape into an equivalent 
  7.                  picture whose elements each have no more points than the limit specified.
  8.                  The callers preference for horizontal versus vertical splitting is accomodated
  9.                  as much as possible.
  10.                 Additionally, a function can be passed to override the default point counting
  11.  
  12.      Version:    Technology:    Quickdraw GX 1.1.x
  13.       
  14.      Copyright:    © 1989-1997 by Apple Computer, Inc., all rights reserved.
  15. */
  16.  
  17. #undef SKIA_BUG_2PICTURE    // Converting to picture doubles transform (mapping)
  18.  
  19. #undef SKIA_BUG_RECT    // My favorite gx graphics bug
  20. #ifdef SKIA_BUG_RECT
  21.                         // Normal
  22. //#define BAD_RECT_TYPE gxRectangleType
  23.                         // Helps BUG3, not BUG1
  24. #define BAD_RECT_TYPE gxPolygonType
  25.                         // prevents clipping problem (BUG1)
  26.                         // Keeps from scrolling death (BUG3) -- but doesnt draw correctly
  27. //#define BAD_RECT_TYPE gxPathType
  28. #endif SKIA_BUG_RECT
  29.  
  30. #undef VERBOSE            // Talk through analysis, if set
  31.  
  32. // allow multiple references to single label
  33. #define resumeLabel(exception)
  34.  
  35. #include "GXToPSBuildConfig.h"
  36. #include <GXGraphics.h>
  37. #include "GXExceptions.h"
  38. #include "ShapeUtilities.h"
  39. #include "IOUtilities.h"
  40.  
  41.  
  42. /* Split the shape in half */
  43. /** 
  44.     D.L
  45.     had to write slightly new version of routine due to the fact that the paramters
  46.     to GXIntersectShape had to be reversed.  The rectangle (shapeSplitter here) needs to
  47.     be the second paramter to intersect shape.  The shape we are splitting needs to be
  48.     the target.  This is to fix bug #1131755.
  49.     Actually, this ends up simplifying the code.  We no longer need to put the shape's
  50.     transform, ink and style on the rectangles since the rectangles are not the target shape
  51.     anymore.  Ken, take a look at my cleanup logic.  I'm not sure if I followed your
  52.     methods.  (DisposeShapeAt, etc…)
  53. **/
  54. OSErr SplitPath(gxShape *thisShape, gxRectangle *shapeSize, Boolean splitH, gxShape *newShapeHalf, gxRectangle *sectSizeHalf);
  55. OSErr SplitPath(gxShape *thisShape, gxRectangle *shapeSize, Boolean splitH, gxShape *newShapeHalf, gxRectangle *sectSizeHalf)
  56. {
  57.     OSErr         status;
  58.     gxShape        shapeSplitter;            // rectangle used to split the shape.
  59.     
  60.     /** Find the rectangles with which to split the shape **/
  61.     
  62.     sectSizeHalf[0].left = sectSizeHalf[1].left = shapeSize->left;
  63.     sectSizeHalf[0].top = sectSizeHalf[1].top = shapeSize->top;
  64.     sectSizeHalf[0].right = sectSizeHalf[1].right = shapeSize->right;
  65.     sectSizeHalf[0].bottom = sectSizeHalf[1].bottom = shapeSize->bottom;
  66.  
  67.     /* Split into halves */
  68.     if (splitH) {    /* Horizontal split? */
  69.         sectSizeHalf[1].left = sectSizeHalf[0].right -= (shapeSize->right - shapeSize->left) >> 1;    /* Divide in half */
  70.     }
  71.     else {    /* Vertical split */
  72.         sectSizeHalf[1].top = sectSizeHalf[0].bottom -= (shapeSize->bottom - shapeSize->top) >> 1;    /* Divide in half */
  73.     }
  74.     
  75.     
  76.     /** Intersect the shape with the two halves **/
  77.  
  78.     shapeSplitter = GXNewRectangle(§SizeHalf[0]);
  79.     nrequire(status = GXGetGraphicsError(nil), failed_makeSplitter);
  80.     
  81.     // First half
  82.     newShapeHalf[0] = GXCopyToShape(nil, *thisShape);
  83.     nrequire(status = GXGetGraphicsError(nil), failed_firstCopy);
  84.     GXIntersectShape(newShapeHalf[0], shapeSplitter);
  85.     nrequire(status = GXGetGraphicsError(nil), failed_firstHalf);
  86.     
  87.     // second half
  88.     newShapeHalf[1] = GXCopyToShape(nil, *thisShape);
  89.     nrequire(status = GXGetGraphicsError(nil), failed_secondCopy);
  90.     GXSetRectangle(shapeSplitter, §SizeHalf[1]);
  91.     GXIntersectShape(newShapeHalf[1], shapeSplitter);
  92.     nrequire(status = GXGetGraphicsError(nil), failed_secondHalf);
  93.  
  94. failed_secondHalf:
  95.  
  96.     if (status != noErr)
  97.         if (newShapeHalf[1] != nil)
  98.             GXDisposeShape(newShapeHalf[1]);        // DL 7/8/97
  99.         
  100. failed_secondCopy:
  101. failed_firstHalf:
  102.  
  103.     if (status != noErr)                                // DL 7/8/97
  104.         if (newShapeHalf[0] != nil)
  105.             GXDisposeShape(newShapeHalf[0]);
  106.         
  107. failed_firstCopy:
  108.  
  109.     GXDisposeShape(shapeSplitter);
  110.  
  111. failed_makeSplitter:
  112.  
  113.     return(status);
  114.     
  115. }
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122. #ifdef leaveParametersReversed
  123. /* Split the shape in half */
  124. OSErr SplitPath(thisShape, shapeSize, splitH, newShapeHalf, sectSizeHalf)
  125.     gxShape *thisShape;
  126.     gxRectangle *shapeSize;
  127.     Boolean splitH;
  128.     gxShape *newShapeHalf;
  129.     gxRectangle *sectSizeHalf;
  130. {
  131.     OSErr status;
  132.  
  133.     /* duplicate rectangle */
  134.     sectSizeHalf[0].left = sectSizeHalf[1].left = shapeSize->left;
  135.     sectSizeHalf[0].top = sectSizeHalf[1].top = shapeSize->top;
  136.     sectSizeHalf[0].right = sectSizeHalf[1].right = shapeSize->right;
  137.     sectSizeHalf[0].bottom = sectSizeHalf[1].bottom = shapeSize->bottom;
  138.  
  139.     /* Split into halves */
  140.     if (splitH) {    /* Horizontal split? */
  141.         sectSizeHalf[1].left = sectSizeHalf[0].right -= (shapeSize->right - shapeSize->left) >> 1;    /* Divide in half */
  142.     }
  143.     else {    /* Vertical split */
  144.         sectSizeHalf[1].top = sectSizeHalf[0].bottom -= (shapeSize->bottom - shapeSize->top) >> 1;    /* Divide in half */
  145.     }
  146.  
  147.     /* Create section areas */
  148.     newShapeHalf[0] = GXNewRectangle(§SizeHalf[0]);
  149.     nrequire(status = GXGetGraphicsError(nil), failed_NewRectangle0);
  150.     newShapeHalf[1] = GXNewRectangle(§SizeHalf[1]);
  151.     nrequire(status = GXGetGraphicsError(nil), failed_NewRectangle1);
  152.     
  153.     /* Give the rectangles the ink of the shape we are splitting so the returned pieces have it */
  154.     GXSetShapeInk(newShapeHalf[0], GXGetShapeInk(*thisShape));
  155.     GXSetShapeInk(newShapeHalf[1], GXGetShapeInk(*thisShape));
  156.  
  157.     /* Give the rectangles the Transform of the shape we are splitting so the returned pieces have it */
  158.     GXSetShapeTransform(newShapeHalf[0], GXGetShapeTransform(*thisShape));
  159.     GXSetShapeTransform(newShapeHalf[1], GXGetShapeTransform(*thisShape));
  160.  
  161.     /* Give the rectangles the Style of the shape we are splitting so the returned pieces have it */
  162.     GXSetShapeStyle(newShapeHalf[0], GXGetShapeStyle(*thisShape));
  163.     GXSetShapeStyle(newShapeHalf[1], GXGetShapeStyle(*thisShape));
  164.  
  165.  
  166. #ifdef SKIA_BUG_RECT
  167.     /* gx graphics bug work-around (rectangles BAD, polygons & paths GOOD!) */
  168.     GXSetShapeType(newShapeHalf[0], BAD_RECT_TYPE);
  169.     GXSetShapeType(newShapeHalf[1], BAD_RECT_TYPE);
  170. #endif SKIA_BUG_RECT
  171.  
  172.     /* Find intersections */
  173.     GXIntersectShape(newShapeHalf[0], *thisShape);
  174.     GXIntersectShape(newShapeHalf[1], *thisShape);
  175.  
  176.     nrequire(status = GXGetGraphicsError(nil), failed_SectShape);
  177.  
  178.     return(noErr);    /* OK */
  179.  
  180.     /* BAILOUTS */
  181. failed_SectShape:
  182.     DisposeShapeAt(&newShapeHalf[1]);    /* Don't litter! (nil pointer out) */
  183. failed_NewRectangle1:
  184.     DisposeShapeAt(&newShapeHalf[0]);    /* Don't litter! (nil pointer out) */
  185. failed_NewRectangle0:
  186.     return(status);    /* Propagate error status */
  187. }
  188. #endif
  189.  
  190.  
  191.  
  192.  
  193. /* Return number of points (all contours)  --  Central in case parms change */
  194. #define CountPoints(theShape, num) ((*countFunct)(theShape, 0, num))
  195.  
  196. /* Must use wrapper here! */
  197. OSErr DefaultCountPoints(gxShape source, long contour, long *num);
  198. OSErr DefaultCountPoints(gxShape source, long contour, long *num)
  199. {
  200.     *num = (GXCountShapePoints(source, contour));    /* Default count function */
  201.     return(noErr);
  202.     
  203. } // DefaultCountPoints
  204.  
  205. #ifdef PATCH_IMAGE    /* Use smaller limit for testing purposes */
  206. # define TRY_LIMIT 20
  207. #else PATCH_IMAGE    /* If this limit is ever hit, the user died of old age! */
  208. # define TRY_LIMIT 0x7FFFFFFF
  209. #endif PATCH_IMAGE
  210.  
  211. /* Chop that shape! */
  212. OSErr ShUDissectPath(gxShape theShape, long limit, Boolean splitH, OSErr (*countFunct)(gxShape aShape, long contour, long *numPoints))
  213. {
  214.     OSErr status;
  215.     long    count1, count2;
  216.     
  217.     gxShape theSource, thisShape, newShapeHalf[2], newShapeQuarter[4];
  218.     gxRectangle shapeSize, sectSizeHalf[2], sectSizeQuarter[4];
  219.     long shapeCount, shapeCountHalf[2],  shapeCountQuarter[4];
  220.     long tries = 0;    /* To prevent infinite loops, or just plain boredom! */
  221.  
  222.     /* Validate shape type */
  223.     switch (GXGetShapeType(theShape)) {
  224.         case gxPolygonType:
  225.         case gxPathType:
  226.             break;    /* These are great! */
  227.         default:
  228.             GXPostGraphicsError(illegal_type_for_shape);    /* Yell real loud! */
  229.             return(illegal_type_for_shape);    /* Bail out */
  230.     }
  231.  
  232.     if (countFunct == nil)    /* Was a counting function supplied? */
  233.         countFunct = DefaultCountPoints;    /* Use default, if not */
  234.  
  235.     /* Create in and out buckets (pictures) */
  236.     GXSetShapeType(theShape, gxPictureType);    /* Convert to picture */
  237.     nrequire(status = GXGetGraphicsError(nil), failed_SetShapeType);
  238.  
  239.     /* Create in bucket */
  240.     theSource = GXCopyToShape(nil, theShape);    /* Make a working copy */
  241.     nrequire(status = GXGetGraphicsError(nil), failed_CopyToShape);
  242.  
  243.     /* Create return bucket */
  244.     GXSetPictureParts(theShape, 1, 1, 0, nil, nil, nil, nil);    /* Clean it out */
  245.     nrequire(status = GXGetGraphicsError(nil), failed_SetPictureParts);
  246.  
  247.     while (GXGetPicture(theSource, nil, nil, nil, nil)  &&  GXGetPictureParts(theSource, 1, 1, &thisShape, nil, nil, nil)) {    /* Call GetPicture() first to void bad index when no elements left */
  248.         
  249.         status = CountPoints(thisShape, &count1);
  250.         nrequire(status, failed_count);
  251.         
  252.         if ( (tries > TRY_LIMIT)  ||  ( (shapeCount = count1) <= limit) )  { /* Small enough? */
  253.  
  254.             GXSetPictureParts(theShape, 0, 0, 1, &thisShape, nil, nil, nil);    /* Append the part */
  255.             GXSetPictureParts(theSource, 1, 1, 0, nil, nil, nil, nil);    /* Delete the part */
  256.             nrequire(status = GXGetGraphicsError(nil), failed_SetPictureParts0);
  257.         }
  258.         else {    /* Need to split */
  259.             ++tries;    /* Log another split */
  260.  
  261.             GXGetShapeBounds(thisShape, (long) 0, &shapeSize);    /* Size the shape */
  262.             nrequire(status = GXGetGraphicsError(nil), failed_GetShapeBounds);
  263.  
  264.             status = SplitPath(&thisShape, &shapeSize, splitH, &newShapeHalf[0], §SizeHalf[0]);
  265.             nrequire(status, failed_SplitPath1);
  266.  
  267.             status = CountPoints(newShapeHalf[0], &count1);
  268.             if (status == noErr)
  269.                 status = CountPoints(newShapeHalf[1], &count2);
  270.             nrequire(status, failed_count);
  271.             
  272.             if (( (shapeCountHalf[0] = count1) < shapeCount)  &&
  273.                 ( (shapeCountHalf[1] = count2) < shapeCount)  ){    /* Improved? */
  274.                 GXSetPictureParts(theSource, 1, 1, 2, &newShapeHalf[0], nil, nil, nil);    /* Replace the part */
  275.                 nrequire(status = GXGetGraphicsError(nil), failed_SetPictureParts1);
  276.             }
  277.             else {    /* Made matters worse! */
  278.                 /* Split other axis */
  279.                 status = SplitPath(&thisShape, &shapeSize, ! splitH, &newShapeQuarter[0], §SizeQuarter[0]);
  280.                 nrequire(status, failed_SplitPath2);
  281.  
  282.                 status = CountPoints(newShapeQuarter[0], &count1);
  283.                 if (status == noErr)
  284.                     status = CountPoints(newShapeQuarter[1], &count2);
  285.                 nrequire(status, failed_count);
  286.     
  287.                 if (( (shapeCountQuarter[0] = count1) < shapeCount)  &&
  288.                     ( (shapeCountQuarter[1] = count2) < shapeCount) ) {    /* Improved? */
  289.                     GXSetPictureParts(theSource, 1, 1, 2, &newShapeQuarter[0], nil, nil, nil);    /* Replace the part */
  290.                     nrequire(status = GXGetGraphicsError(nil), failed_SetPictureParts2);
  291.                 }
  292.                 else {    /* Do lesser of the evils */
  293.                     GXSetPictureParts(theSource, 1, 1, 2, &newShapeHalf[0], nil, nil, nil);    /* Replace the part */
  294.                     nrequire(status = GXGetGraphicsError(nil), failed_SetPictureParts2b);
  295.                 }
  296.  
  297.                 GXDisposeShape(newShapeQuarter[0]);    /* Don't litter! */
  298.                 GXDisposeShape(newShapeQuarter[1]);    /* Don't litter! */
  299.             }
  300.  
  301.             GXDisposeShape(newShapeHalf[0]);    /* Don't litter! */
  302.             GXDisposeShape(newShapeHalf[1]);    /* Don't litter! */
  303.         }
  304.     }
  305.     GXDisposeShape(theSource);    /* Don't litter! */
  306.     return(noErr);    /* OK */
  307.  
  308.     /* BAILOUTS */
  309. failed_SetPictureParts2b:
  310. failed_SetPictureParts2:
  311. failed_SetPictureParts1:
  312. failed_SetPictureParts0:
  313. failed_SplitPath2:
  314. failed_SplitPath1:
  315. failed_GetShapeBounds:
  316. failed_SetPictureParts:
  317. failed_count:
  318.     GXDisposeShape(theSource);    /* Don't litter! */
  319. failed_CopyToShape:
  320. #ifndef SKIA_BUG_2PICTURE
  321. failed_DisposeTransform:
  322. failed_NewTransform:
  323. failed_GetPictureParts:
  324. #endif SKIA_BUG_2PICTURE
  325. failed_SetShapeType:
  326.  
  327.     return(status);    /* Propagate error */
  328. }
  329.